package com.lry;

import com.lry.config.MessageStoreConfig;
import com.lry.util.LibC;
import com.sun.jna.NativeLong;
import com.sun.jna.Pointer;
import lombok.extern.slf4j.Slf4j;
import sun.nio.ch.DirectBuffer;

import java.nio.ByteBuffer;
import java.util.Deque;
import java.util.concurrent.ConcurrentLinkedDeque;

@Slf4j
public class TransientStorePool {

    private final int poolSize;

    private final int fileSize;

    private final Deque<ByteBuffer> availableBuffers;

    private final MessageStoreConfig storeConfig;

    public TransientStorePool(MessageStoreConfig storeConfig){
        this.storeConfig = storeConfig;
        this.poolSize = storeConfig.getTransientStorePoolSize();
        this.fileSize = storeConfig.getMappedFileSizeCommitLog();
        this.availableBuffers = new ConcurrentLinkedDeque<>();
        init();
    }

    public void init(){
        for(int i=0;i< poolSize;i++){
            ByteBuffer byteBuffer = ByteBuffer.allocateDirect(fileSize);

            final long address = ((DirectBuffer)byteBuffer).address();

            Pointer pointer = new Pointer(address);

            //开启内存锁定，防止被swap 置换出内存
//            LibC.INSTANCE.mlock(pointer,new NativeLong(fileSize));
            availableBuffers.offer(byteBuffer);
        }
    }


    public void destroy(){
        for (ByteBuffer byteBuffer : availableBuffers) {
            final long address = ((DirectBuffer) byteBuffer).address();
            Pointer pointer = new Pointer(address);
            LibC.INSTANCE.munlock(pointer,new NativeLong(fileSize));
        }
    }

    public void returnBuffer(ByteBuffer byteBuffer){
        byteBuffer.position(0);
        byteBuffer.limit(fileSize);
        this.availableBuffers.offerFirst(byteBuffer);
    }


    public ByteBuffer borrowBuffer(){
        ByteBuffer byteBuffer = this.availableBuffers.pollFirst();
        if (availableBuffers.size() < poolSize * 0.4) {
            log.warn("TransientStorePool only remain {} sheets.", availableBuffers.size());
        }
        return byteBuffer;
    }

    public int availableBufferNums() {
        if (storeConfig.isTransientStorePoolEnable()) {
            return availableBuffers.size();
        }
        return Integer.MAX_VALUE;
    }


}
